package im.elephas.fanfouapi;

import im.elephas.fanfouapi.events.IChangeEvent;
import im.elephas.fanfouapi.events.IErrorEvent;
import im.elephas.fanfouapi.events.IStatusesEvent;
import im.elephas.fanfouapi.events.IUpdateEvent;
import im.elephas.fanfouapi.events.IUsersEvent;
import im.elephas.fanfouapi.events.IVerifyEvent;
import im.elephas.fanfouapi.items.UserItem;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.NameValuePair;
import org.apache.http.auth.AuthScheme;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.AuthState;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.xmlpull.v1.XmlPullParserException;

import android.net.Credentials;

public final class FanfouApi {

	private static class PreemptiveAuth implements HttpRequestInterceptor {

		@Override
		public void process(final HttpRequest request, final HttpContext context)
				throws HttpException, IOException {

			AuthState authState = (AuthState) context
					.getAttribute(ClientContext.TARGET_AUTH_STATE);

			if (authState.getAuthScheme() == null) {
				AuthScheme authScheme = (AuthScheme) context
						.getAttribute("preemptive-auth");
				CredentialsProvider credsProvider = (CredentialsProvider) context
						.getAttribute(ClientContext.CREDS_PROVIDER);
				if (authScheme != null) {
					Credentials creds = (Credentials) credsProvider
							.getCredentials(AuthScope.ANY);
					if (creds == null) {
						throw new HttpException();
					}
					authState.setAuthScheme(authScheme);
					authState
							.setCredentials((org.apache.http.auth.Credentials) creds);
				}
			}
		}
	}

	public static FanfouApi getInstance() {
		if (mFanfouApi == null) {
			synchronized (FanfouApi.class) {
				if (mFanfouApi == null) {
					mFanfouApi = new FanfouApi();
				}
			}
		}
		return mFanfouApi;
	}

	private String username;
	private String password;

	private UserItem user;

	private DefaultHttpClient httpclient;

	private volatile static FanfouApi mFanfouApi;
	private List<String> firendsListUserItems;

	private List<String> followersListUserItems;

	private FanfouApi() {
	}

	public Object clone() throws CloneNotSupportedException {
		throw new CloneNotSupportedException();
	}

	public void getFavorite(final int count, final int page,
			final IStatusesEvent ise, final IErrorEvent iee) {
		Thread t = new Thread(new Runnable() {

			@Override
			public void run() {
				String xml = null;
				try {
					xml = getStringFromApi(FanfouUrl.FANFOU_FAVORTITES
							+ "?count=" + count + "&page=" + page);
					ise.statusesHandler(FanfouXml.getStatuses(xml));
				} catch (Exception e) {
					iee.errorHandler();
				}
			}
		});
		t.start();
	}

	public List<String> getFirendsListIds() {
		return firendsListUserItems;
	}

	public void updateFollowerIds(final String id)
			throws ClientProtocolException, IOException, XmlPullParserException {
		String str = getStringFromApi(FanfouUrl.FANFOU_FOLLOWERS_IDS + id
				+ ".xml");
		List<String> ls = FanfouXml.getIds(str);
		followersListUserItems = ls;
	}

	public void getFollowers(final String id, final IUsersEvent iue,
			final IErrorEvent iee) {
		Thread t = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					String str = getStringFromApi(FanfouUrl.FANFOU_USERS_FOLLOWERS
							+ "?id=" + id);
					List<UserItem> lui = FanfouXml.getUsers(str);
					iue.usersHandler(lui);
				} catch (Exception e) {
					iee.errorHandler();
				}
			}
		});
		t.start();
	}

	public List<String> getFollowersListIds() {
		return followersListUserItems;
	}

	public void updateFriendIds(final String id)
			throws ClientProtocolException, IOException, XmlPullParserException {
		String str = getStringFromApi(FanfouUrl.FANFOU_FRIENDS_IDS + id
				+ ".xml");
		List<String> ls = FanfouXml.getIds(str);
		firendsListUserItems = ls;
	}

	public void getFriends(final String id, final IUsersEvent iue,
			final IErrorEvent iee) {
		Thread t = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					String str = getStringFromApi(FanfouUrl.FANFOU_USERS_FOLLOWERS
							+ "?id=" + id);
					List<UserItem> lui = FanfouXml.getUsers(str);
					iue.usersHandler(lui);
				} catch (Exception e) {
					e.printStackTrace();
					iee.errorHandler();
				}
			}
		});
		t.start();
	}

	public void getFriendsTimeline(final int count, final int page,
			final IStatusesEvent ise, final IErrorEvent iee) {
		Thread t = new Thread(new Runnable() {

			@Override
			public void run() {
				String xml = null;
				try {
					xml = getStringFromApi(FanfouUrl.FANFOU_STATUES_FRIENDS_TIMELINE
							+ "?count=" + count + "&page=" + page);
					ise.statusesHandler(FanfouXml.getStatuses(xml));
				} catch (Exception e) {
					iee.errorHandler();
				}
			}
		});
		t.start();
	}

	public String getPassword() {
		return password;
	}

	public void getPublicTimeline(final int count, final IStatusesEvent ise,
			final IErrorEvent iee) {
		Thread t = new Thread(new Runnable() {

			@Override
			public void run() {
				String xml = null;
				try {
					xml = getStringFromApi(FanfouUrl.FANFOU_STATUES_PUBLIC_TIMELINE
							+ "?count=" + count);
					ise.statusesHandler(FanfouXml.getStatuses(xml));
				} catch (Exception e) {
					iee.errorHandler();
				}
			}
		});
		t.start();
	}

	public void getReplyTimeline(final int count, final int page,
			final IStatusesEvent ise, final IErrorEvent iee) {
		Thread t = new Thread(new Runnable() {

			@Override
			public void run() {
				String xml = null;
				try {
					xml = getStringFromApi(FanfouUrl.FANFOU_STATUES_REPLIES
							+ "?count=" + count + "&page=" + page);
					ise.statusesHandler(FanfouXml.getStatuses(xml));
				} catch (Exception e) {
					iee.errorHandler();
				}
			}
		});
		t.start();
	}

	private String getStringFromApi(String api) throws ClientProtocolException,
			IOException {
		HttpGet httpget = new HttpGet(api);
		ResponseHandler<String> responseHandler = new BasicResponseHandler();
		String str = httpclient.execute(httpget, responseHandler);
		return str;
	}

	public String getUsername() {
		return username;
	}

	public void getUserTimeline(final int count, final int page,
			final IStatusesEvent ise, final IErrorEvent iee) {
		Thread t = new Thread(new Runnable() {

			@Override
			public void run() {
				String xml = null;
				try {
					xml = getStringFromApi(FanfouUrl.FANFOU_STATUES_USER_TIMELINE
							+ "?count=" + count + "&page=" + page);
					ise.statusesHandler(FanfouXml.getStatuses(xml));
				} catch (Exception e) {
					iee.errorHandler();
				}
			}
		});
		t.start();
	}

	public void getUserTimeline(final int count, final int page,
			final String id, final IStatusesEvent ise, final IErrorEvent iee) {
		Thread t = new Thread(new Runnable() {

			@Override
			public void run() {
				String xml = null;
				try {
					xml = getStringFromApi(FanfouUrl.FANFOU_STATUES_USER_TIMELINE
							+ "?id=" + id + "&count=" + count + "&page=" + page);
					ise.statusesHandler(FanfouXml.getStatuses(xml));
				} catch (Exception e) {
					iee.errorHandler();
				}
			}
		});
		t.start();
	}

	public void replyMessage(final String status, final String replyId,
			final IUpdateEvent iue, final IErrorEvent iee) {
		Thread t = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					ArrayList<NameValuePair> nvps = new ArrayList<NameValuePair>();
					nvps.add(new BasicNameValuePair("status", status));
					nvps.add(new BasicNameValuePair("in_reply_to_status_id",
							replyId));
					nvps.add(new BasicNameValuePair("source", "androfan"));
					String str = updateMessageToApi(
							FanfouUrl.FANFOU_STATUES_UPDATE, nvps);
					iue.updateHandler(str);
				} catch (Exception e) {
					iee.errorHandler();
				}
			}
		});
		t.start();

	}

	public void setAccount(String username, String password) {
		this.username = username;
		this.password = password;

		httpclient = new DefaultHttpClient();
		httpclient.getCredentialsProvider().setCredentials(AuthScope.ANY,
				new UsernamePasswordCredentials(username, password));
		httpclient.addRequestInterceptor(new PreemptiveAuth(), 0);
	}

	public void updateMessage(final String status, final IUpdateEvent iue,
			final IErrorEvent iee) {
		Thread t = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					ArrayList<NameValuePair> nvps = new ArrayList<NameValuePair>();
					nvps.add(new BasicNameValuePair("status", status));
					nvps.add(new BasicNameValuePair("source", "androfan"));
					String str = updateMessageToApi(
							FanfouUrl.FANFOU_STATUES_UPDATE, nvps);
					iue.updateHandler(str);
				} catch (Exception e) {
					iee.errorHandler();
				}
			}
		});
		t.start();
	}

	private String updateMessageToApi(String api, List<NameValuePair> nvps)
			throws ClientProtocolException, IOException {
		HttpPost httppost = new HttpPost(api);
		httppost.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
		ResponseHandler<String> responseHandler = new BasicResponseHandler();
		String str = httpclient.execute(httppost, responseHandler);
		return str;
	}

	public void loginAccount(final IVerifyEvent ive) {
		Thread t = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					String str = getStringFromApi(FanfouUrl.FANFOU_ACCOUNT_VERIFY);
					List<UserItem> lu = FanfouXml.getUsers(str);
					if (lu.get(0) != null) {
						mFanfouApi.user = lu.get(0);
						updateFriendIds(mFanfouApi.getUser().getId());
						updateFollowerIds(mFanfouApi.getUser().getId());
						ive.verifyHandler(true);
					} else
						ive.verifyHandler(false);
				} catch (Exception e) {
					ive.verifyHandler(false);
				}
			}
		});
		t.start();
	}

	public void createFriendship(final String id, final IChangeEvent ice,
			final IErrorEvent iee) {
		Thread t = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					List<NameValuePair> nvps = new ArrayList<NameValuePair>();
					nvps.add(new BasicNameValuePair("id", id));
					updateMessageToApi(FanfouUrl.FANFOU_FRIENDSHIPS_CREATE,
							nvps);
					updateFriendIds(mFanfouApi.getUser().getId());
					ice.changeHandler(true);
				} catch (Exception e) {
					iee.errorHandler();
				}
			}
		});
		t.start();
	}

	public void destroyFriendship(final String id, final IChangeEvent ice,
			final IErrorEvent iee) {
		Thread t = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					List<NameValuePair> nvps = new ArrayList<NameValuePair>();
					nvps.add(new BasicNameValuePair("id", id));
					updateMessageToApi(FanfouUrl.FANFOU_FRIENDSHIPS_DESTROY,
							nvps);
					updateFriendIds(mFanfouApi.getUser().getId());
					ice.changeHandler(true);
				} catch (Exception e) {
					iee.errorHandler();
				}
			}
		});
		t.start();
	}

	public void createFavorite(final String id, final IChangeEvent ice,
			final IErrorEvent iee) {
		Thread t = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					List<NameValuePair> nvps = new ArrayList<NameValuePair>();
					nvps.add(new BasicNameValuePair("id", id));
					updateMessageToApi(FanfouUrl.FANFOU_FAVORTITES_CREATE + id
							+ ".xml", nvps);
					ice.changeHandler(true);
				} catch (Exception e) {
					iee.errorHandler();
				}
			}
		});
		t.start();
	}

	public void destroyFavorite(final String id, final IChangeEvent ice,
			final IErrorEvent iee) {
		Thread t = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					List<NameValuePair> nvps = new ArrayList<NameValuePair>();
					nvps.add(new BasicNameValuePair("id", id));
					updateMessageToApi(FanfouUrl.FANFOU_FAVORTITES_DESTROY + id
							+ ".xml", nvps);
					ice.changeHandler(true);
				} catch (Exception e) {
					iee.errorHandler();
				}
			}
		});
		t.start();
	}

	public UserItem getUser() {
		return user;
	}

}
